// Copyright (c) 1996-2002 John Lyon-Smith. All rights reserved.

#pragma once

#include <wxtl\Base.h>
#include <wxtl\ComHelp.h>
#include <wxtl\Interlock.h>

#define BEGIN_COM_IUNKNOWN_IMPL() \
	STDMETHOD_(ULONG, AddRef)() { return ComUnknown::AddRef(); } \
	STDMETHOD_(ULONG, Release)() { return ComUnknown::Release(); } \
	STDMETHODIMP QueryInterface(REFIID riid, void **ppInterface) \
	{ \
		HRESULT hr = ComUnknown::QueryInterface(riid, ppInterface); \
		if (SUCCEEDED(hr)) \
			return hr;

#define COM_IUNKNOWN_INTERFACE(iid, iface) \
		if (riid == iid) \
			*ppInterface = static_cast<iface *>(this);

#define END_COM_IUNKNOWN_IMPL() \
		else \
		{ \
			*ppInterface = NULL; \
			return E_NOINTERFACE; \
		} \
		reinterpret_cast<IUnknown *>(*ppInterface)->AddRef(); \
		return S_OK; \
	}

namespace wxtl
{
	class ComUnknown : public IUnknown
	{
		public:
			ComUnknown()
			{
				m_refCount = 0;
			}
			
			virtual ~ComUnknown() {}
		
			// IUnknown
			STDMETHOD_(ULONG, AddRef)()
			{
  				return Increment(&m_refCount);
			}

			STDMETHOD_(ULONG, Release)()
			{    
				long refCount;

				refCount = Decrement(&m_refCount);
				if (refCount == 0) 
					delete this;
			    
				return refCount;
			}

			STDMETHOD(QueryInterface)(REFIID riid, void **ppInterface)
			{    
				#if _DEBUG && _WXTL_QI_TRACE
				WXTRACE("ComUnknown: QI for %s\n", stringFromGuid(riid).c_str());
				#endif

				if ( riid == IID_IUnknown )
					*ppInterface = static_cast<IUnknown *>( this );	
				else
				{
					*ppInterface = NULL;                  
			        
					return E_NOINTERFACE;
				}
			    
				reinterpret_cast<IUnknown *>(*ppInterface )->AddRef();
			    
				return S_OK;
			}

		private:
			long m_refCount;
	};
};
